#ifndef EVENT_EVENT_H
#define EVENT_EVENT_H

#include <set>

#define forall(it,X) for(typeof((X).begin()) it=(X).begin();it!=(X).end();it++)

class NullType {};

// ---------------------------------------------------------------------

template<
        class Param0 = NullType,
        class Param1 = NullType,
        class Param2 = NullType,
        class Param3 = NullType
> class BaseFunctor;

template<
        class CLASS_T,
        class Param0 = NullType,
        class Param1 = NullType,
        class Param2 = NullType,
        class Param3 = NullType
> class Functor;

template<
        class Param0 = NullType,
        class Param1 = NullType,
        class Param2 = NullType,
        class Param3 = NullType
> class Event;

// ---------------------------------------------------------------------

template <>
class BaseFunctor<NullType, NullType, NullType, NullType>
{
    public:
    
        virtual void operator () () const = 0;
        
    protected:
    
        BaseFunctor() {}
};

template <class CLASS_T>
class Functor<CLASS_T, NullType, NullType, NullType, NullType>
    : public BaseFunctor<>
{
    public:
        
        typedef void (CLASS_T::*MemberFn)();
        
        Functor( CLASS_T* class_instance, MemberFn member_function_ptr )
        {
            _class_instance = class_instance;
            _member_function_ptr = member_function_ptr;
        }
        
        void operator () () const
        {
            (_class_instance->*_member_function_ptr)();
        }
        
    private:
        
        CLASS_T* _class_instance;
        
        MemberFn _member_function_ptr;
};

template <>
class Event<NullType, NullType, NullType, NullType>
{
    public:
    
        void Notify() const
        {
            forall(it,callbacks)
                (**it)();
        }
        
        bool Subscribe(BaseFunctor<>* callback)
        {
            if( callbacks.insert(callback).second == false )
                return false;
            return true;
        }
        
        bool Unsubscribe(BaseFunctor<>* callback)
        {
            if( callbacks.erase(callback) < 1)
                return false;
            return true;
        }
        
    private:
    
        std::set<BaseFunctor<>*> callbacks;
};

// ---------------------------------------------------------------------

template <class P1_T>
class BaseFunctor<P1_T, NullType, NullType, NullType>
{
    public:
    
        virtual void operator () (P1_T) const = 0;
        
    protected:
    
        BaseFunctor() {}
};

template <class CLASS_T, class P1_T>
class Functor<CLASS_T, P1_T, NullType, NullType, NullType>
    : public BaseFunctor<P1_T>
{
    public:
        
        typedef void (CLASS_T::*MemberFn)(P1_T);
        
        Functor( CLASS_T* class_instance, MemberFn member_function_ptr )
        {
            _class_instance = class_instance;
            _member_function_ptr = member_function_ptr;
        }
        
        void operator () (P1_T p1) const
        {
            (_class_instance->*_member_function_ptr)(p1);
        }
        
    private:
        
        CLASS_T* _class_instance;
        
        MemberFn _member_function_ptr;
};

template <class P1_T>
class Event<P1_T, NullType, NullType, NullType>
{
    public:
    
        void Notify(P1_T p1) const
        {
            forall(it,callbacks)
                (**it)(p1);
        }
        
        bool Subscribe(BaseFunctor<P1_T>* callback)
        {
            if( callbacks.insert(callback).second == false )
                return false;
            return true;
        }
        
        bool Unsubscribe(BaseFunctor<P1_T>* callback)
        {
            if( callbacks.erase(callback) < 1)
                return false;
            return true;
        }
        
    private:
    
        std::set<BaseFunctor<P1_T>*> callbacks;
};

// ---------------------------------------------------------------------

template <class P1_T, class P2_T>
class BaseFunctor<P1_T, P2_T, NullType, NullType>
{
    public:
    
        virtual void operator () (P1_T, P2_T) const = 0;
        
    protected:
    
        BaseFunctor() {}
};

template <class CLASS_T, class P1_T, class P2_T>
class Functor<CLASS_T, P1_T, P2_T, NullType, NullType>
    : public BaseFunctor<P1_T, P2_T>
{
    public:
        
        typedef void (CLASS_T::*MemberFn)(P1_T, P2_T);
        
        Functor( CLASS_T* class_instance, MemberFn member_function_ptr )
        {
            _class_instance = class_instance;
            _member_function_ptr = member_function_ptr;
        }
        
        void operator () (P1_T p1, P2_T p2) const
        {
            (_class_instance->*_member_function_ptr)(p1,p2);
        }
        
    private:
        
        CLASS_T* _class_instance;
        
        MemberFn _member_function_ptr;
};

template <class P1_T, class P2_T>
class Event<P1_T, P2_T, NullType, NullType>
{
    public:
    
        void Notify(P1_T p1, P2_T p2) const
        {
            forall(it,callbacks)
                (**it)(p1,p2);
        }
        
        bool Subscribe(BaseFunctor<P1_T,P2_T>* callback)
        {
            if( callbacks.insert(callback).second == false )
                return false;
            return true;
        }
        
        bool Unsubscribe(BaseFunctor<P1_T,P2_T>* callback)
        {
            if( callbacks.erase(callback) < 1)
                return false;
            return true;
        }
        
    private:
    
        std::set<BaseFunctor<P1_T,P2_T>*> callbacks;
};

// ---------------------------------------------------------------------

template <class P1_T, class P2_T, class P3_T>
class BaseFunctor<P1_T, P2_T, P3_T, NullType>
{
    public:
    
        virtual void operator () (P1_T, P2_T, P3_T) const = 0;
        
    protected:
    
        BaseFunctor() {}
};

template <class CLASS_T, class P1_T, class P2_T, class P3_T>
class Functor<CLASS_T, P1_T, P2_T, P3_T, NullType>
    : public BaseFunctor<P1_T, P2_T, P3_T>
{
    public:
        
        typedef void (CLASS_T::*MemberFn)(P1_T, P2_T, P3_T);
        
        Functor( CLASS_T* class_instance, MemberFn member_function_ptr )
        {
            _class_instance = class_instance;
            _member_function_ptr = member_function_ptr;
        }
        
        void operator () (P1_T p1, P2_T p2, P3_T p3) const
        {
            (_class_instance->*_member_function_ptr)(p1,p2,p3);
        }
        
    private:
        
        CLASS_T* _class_instance;
        
        MemberFn _member_function_ptr;
};

template <class P1_T, class P2_T, class P3_T>
class Event<P1_T, P2_T, P3_T, NullType>
{
    public:
    
        void Notify(P1_T p1, P2_T p2, P3_T p3) const
        {
            forall(it,callbacks)
                (**it)(p1,p2,p3);
        }
        
        bool Subscribe(BaseFunctor<P1_T,P2_T,P3_T>* callback)
        {
            if( callbacks.insert(callback).second == false )
                return false;
            return true;
        }
        
        bool Unsubscribe(BaseFunctor<P1_T,P2_T,P3_T>* callback)
        {
            if( callbacks.erase(callback) < 1)
                return false;
            return true;
        }
        
    private:
    
        std::set<BaseFunctor<P1_T,P2_T,P3_T>*> callbacks;
};

// ---------------------------------------------------------------------

#endif
